<template>
  <div class="form">
    <a-row class="form-item">
      <a-col :span="labelCol">关系图数据</a-col>
      <a-col :span="wrapperCol">
        <div v-if="widgetType !== widgetTypeEnum.system" class="dataset-name">
          {{ datasetName }}
        </div>
        <a-select
          v-else
          :value="formData.dataId"
          size="small"
          placeholder="请选择graph数据"
          v-bind="commonFormProps"
          @change="(value) => handleDatasetChange(value, 'graph')"
        >
          <a-select-option v-for="item in graphList" :key="item">
            {{ item }}
          </a-select-option>
        </a-select>
      </a-col>
    </a-row>
    <!-- graph-lineChart demo start -->
    <template v-if="isGraphLineChart">
      <a-row class="form-item">
        <a-col :span="labelCol">折线图数据</a-col>
        <a-col :span="wrapperCol">
          <a-select
            :value="formData.subDataId"
            size="small"
            placeholder="请选择折线图数据"
            v-bind="commonFormProps"
            @change="(value) => handleDatasetChange(value, 'lineChart')"
          >
            <a-select-option v-for="item in datasetList.dataset" :key="item.id">
              {{ item.name }}
            </a-select-option>
          </a-select>
        </a-col>
      </a-row>
      <a-row class="form-item">
        <a-col :span="labelCol"
          >关联字段
          <a-tooltip>
            <template slot="title">
              此字段决定折线图在网络图中的节点位置
            </template>
            <a-icon-font type="iconinfo-cirlce-o" />
          </a-tooltip>
        </a-col>
        <a-col :span="wrapperCol">
          <a-select
            :value="formData.combineField"
            size="small"
            placeholder="请选择关联字段"
            v-bind="commonFormProps"
            @change="handleCombineFieldChange"
          >
            <a-select-option
              v-for="item in datasetTableColumn"
              :key="item.name"
            >
              {{ item.name }}
            </a-select-option>
          </a-select>
        </a-col>
      </a-row>
    </template>

    <div v-if="isGraphLineChart" class="panel">
      <div class="panel-title" @click="showFlag = !showFlag">
        <div class="panel-title-hr"></div>
        数据
        <a-icon :type="showFlag ? 'down' : 'right'" />
      </div>
      <div v-show="showFlag" class="group-form-item">
        <div>折线图</div>
        <a-row class="form-item">
          <a-col :span="labelCol">维度</a-col>
          <a-col :span="wrapperCol">
            <column-select
              :value="formData.labelKeyObj || { sort: 'desc' }"
              v-bind="commonFormProps"
              :options="labelKeyObjOptions()"
              @sortChange="(value) => onSortChange('labelKeyObj', value)"
              @change="(value) => onFormValueChange('labelKeyObj', value)"
            />
          </a-col>
        </a-row>
        <a-row class="form-item">
          <a-col :span="labelCol">度量</a-col>
          <a-col :span="wrapperCol">
            <multiple-select
              :value="
                formData.valueKeyObjList || [
                  { value: '', sort: '', func: 'sum' },
                ]
              "
              v-bind="commonFormProps"
              :options="valueKeyObjOptions()"
              :is-single="true"
              :is-sortable="false"
              :form-data="formData"
              @change="(value) => onFormValueChange('valueKeyObjList', value)"
            />
          </a-col>
        </a-row>
        <a-row class="form-item">
          <a-col :span="labelCol">TopN</a-col>
          <a-col :span="wrapperCol">
            <a-input-number
              :value="formData.topN"
              v-bind="commonFormProps"
              @blur="onTopNChange"
            />
          </a-col>
        </a-row>
      </div>
    </div>
    <!-- graph-lineChart demo end -->

    <property-form
      :form-data="formData"
      :panel-list="panelList"
      @change="onPropertyChange"
    />

    <interact-form
      v-if="relateWidgets.length > 0"
      :checked-widgets="checkedWidgets"
      :relate-widgets="relateWidgets"
      :current-name="currentWidgetTitle ? currentWidgetTitle : currentWidgetId"
      @change="onRelateWidgetsChange"
    />
  </div>
</template>

<script lang="ts">
import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
import {
  convertFormDataToWidgetJson,
  IKeyValue,
  widgetTypeEnum,
} from '@/components/common/VisualizationDashboard/util'
import {
  IPanel,
  IColumn,
  IDatasetList,
} from '@/components/common/VisualizationDashboard/interface'
import { loadListFiles } from '@/api/graph-analysis'
import { queryWidgetColumn } from '@/api/widget'
import MultipleSelect from '@/components/form/multiple-select.vue'
import ColumnSelect from '@/components/common/VisualizationDashboard/CustomizeComponent/ColumnSelect.vue'
import PropertyForm from '@/components/common/VisualizationDashboard/PropertyForm.vue'
import InteractForm from '@/components/common/VisualizationDashboard/InteractForm.vue'
import VisualizationStore from '@/store/modules/visualization'
import { cloneDeep, isEqual } from 'lodash'

@Component({
  components: {
    MultipleSelect,
    ColumnSelect,
    PropertyForm,
    InteractForm,
  },
})
export default class GraphForm extends Vue {
  @Prop() chartType!: string
  @Prop({ default: 'system' }) widgetType!: 'system' | 'dataset' | 'pipeline' // system-系统组件 pipeline - pipeline组件
  @Prop({ default: () => ({}) }) formData!: IKeyValue
  @Prop({ default: () => [] }) datasetList!: IDatasetList // 数据集列表
  @Prop({ default: '' }) projectId!: '' // 项目id，查询数据集相关列时校验权限用
  @Prop({ default: () => [] }) panelList!: IPanel[]

  @Prop({
    type: Number,
    required: false,
    default() {
      return 8
    },
  })
  labelCol!: number

  @Prop({
    type: Number,
    required: false,
    default() {
      return 16
    },
  })
  wrapperCol!: number

  private widgetTypeEnum = widgetTypeEnum // widget 类型：系统组件、pipeline组件，目前只有系统组件会传该字段
  private queryColumnParams = {
    curPage: 1,
    pageSize: 5,
    projectId: this.projectId,
  }
  private datasetTableColumn: IColumn[] = []
  private commonFormProps = {
    size: 'small',
  }
  private graphList: string[] = []
  private checkedWidgets: string[] = [] // 勾选的widget
  private relateWidgets: any[] = [] // 可关联图表的全部list

  private graphDataId: string = ''
  private lineChartDataId: string = ''
  private showFlag: boolean = true // 是否展开面板
  private defaultSubChartOptions = {
    // graph-linechart的默认配置
    subWidthSize: 200,
    lineSmooth: true,
    axisScaleType: 'linear',
    colors: [
      '#5760e6',
      '#FBC94B',
      '#65DCB8',
      '#EF7D52',
      '#F596C6',
      '#687B9D',
      '#5EC6D7',
      '#FFA65E',
    ],
  }

  mounted() {
    this.fetchGraphList()
    this.initGraph()
    this.initRelateWidgets()

    if (this.isGraphLineChart) {
      this.$set(this.formData, 'isAggr', false) // 一定是非聚合的，拿详细数据
      this.$set(this.formData, 'topN', 200)
    }
  }

  @Watch('interactionJson')
  private onInteractionJsonChange(newValue: any, oldValue: any) {
    if (isEqual(newValue, oldValue)) {
      return
    }
    this.initRelateWidgets()
  }

  /**
   * 初始化关联list
   */
  private initRelateWidgets() {
    const gridList = VisualizationStore.gridList.filter(
      (gridItem) =>
        gridItem.widgetId &&
        gridItem.i !== VisualizationStore.currentGridItem?.i &&
        gridItem.chartType !== 'text'
    )
    if (this.interactionJson && this.interactionJson.relateWidgets) {
      // widget 中有记录时 list以当前画布中的gridList为准，再同步interactionJson中的关联状态
      const relateWidgetsIds = new Set(
        this.interactionJson.relateWidgets.map((widget: any) => widget.widgetId)
      )
      this.relateWidgets = this.interactionJson.relateWidgets
      this.relateWidgets = gridList.map((item) => {
        if (!relateWidgetsIds.has(item.widgetId)) {
          // 不存在widget的记录中，新增一条记录
          return {
            widgetId: item.widgetId,
            taskId: item.chartOptions.dataId,
            tableName: null,
            chartName: null,
            status: 'available',
            connected: false,
            loseConnected: false,
            // xattrStr: 'species',
            // xattrValueType: 'varchar',
            disabled: false,
            label: item.chartOptions.title || item.widgetId,
            value: item.widgetId,
          }
        }
        // 否则直接返回widget记录中的内容
        return {
          ...this.relateWidgets.filter(
            (widget) => widget.widgetId === item.widgetId
          )[0],
          label: item.chartOptions.title || item.widgetId,
        }
      })
      this.checkedWidgets = this.relateWidgets
        .filter((item) => {
          return item.status === 'connected'
        })
        .map((item) => item.widgetId)
    } else {
      // widget中没有记录时，直接从gridList 进行初始化
      this.checkedWidgets = []
      this.relateWidgets = gridList.map((gridItem) => {
        return {
          widgetId: gridItem.widgetId,
          taskId: gridItem.chartOptions.dataId,
          tableName: null,
          chartName: null,
          status: 'available',
          connected: false,
          loseConnected: false,
          // xattrStr: 'species',
          // xattrValueType: 'varchar',
          disabled: false,
          label: gridItem.chartOptions.title || gridItem.widgetId,
          value: gridItem.widgetId,
        }
      })
    }
  }

  /**
   * 初始化graph
   */
  private initGraph() {
    // if (this.formData.dataId) {
    //   this.$emit('change', 'dataId', {
    //     id: this.formData.dataId,
    //     type: 'dataset',
    //     subDataId: this.formData.subDataId,
    //   })
    // }
    if (this.formData.subDataId) {
      this.fetchDatasetColumns(this.formData.subDataId)
    }
  }

  /**
   * 临时demo
   */
  private get isGraphLineChart() {
    return this.chartType === 'graphLineChart'
  }

  private get currentWidgetId() {
    return VisualizationStore.currentGridItem?.widgetId
  }

  private get currentWidgetTitle() {
    return VisualizationStore.currentGridItem?.chartOptions?.title
  }

  /**
   * currentGridItem 中记录的关联列表信息
   */
  private get interactionJson() {
    return VisualizationStore.currentGridItem?.interactionJson
  }

  /**
   * 关联关系变化
   */
  private onRelateWidgetsChange(checkedList: any[]) {
    console.log(checkedList)
    const list: any[] = cloneDeep(this.relateWidgets)
    list.forEach((item) => {
      // delete item.label
      // delete item.value
      if (checkedList.includes(item.widgetId)) {
        item.status = 'connected'
      } else {
        item.status = 'available'
      }
    })

    this.$emit('relateWidgetsChange', {
      type: 'interact',
      data: {
        relateWidgets: list,
      },
    })
  }

  private labelKeyObjOptions() {
    return this.datasetTableColumn.map((column) => ({
      value: column.name,
      text: column.name,
      desc: column.desc,
      disabled: (this.formData.valueKeyObjList || []).some(
        (v: any) => v.value === column.name
      ),
    }))
  }

  private valueKeyObjOptions() {
    const { formData } = this
    const columns = this.datasetTableColumn.filter(
      (column) => column.desc === 'int' || column.desc === 'decimal'
    )
    return columns.map((column) => ({
      value: column.name,
      text: column.name,
      disabled: column.name === formData.labelKeyObj?.value,
    }))
  }

  /**
   * 获取graph数据list
   */
  private async fetchGraphList() {
    const response = await loadListFiles()
    if (response.data.code === 100) {
      this.graphList = response.data.result
    } else {
      this.$message.error(
        response.data.message ||
          response.data.message.tips ||
          '获取数据集失败，请稍候再试'
      )
    }
  }

  /**
   * 获取数据集相关列
   */
  private async handleDatasetChange(value: string, type: string = 'graph') {
    if (!value) {
      return
    }
    if (this.isGraphLineChart) {
      // 需要校验两个数据集都被选上再请求数据
      if (type === 'graph') {
        this.graphDataId = value
        this.$set(this.formData, 'dataId', value)
        this.$set(this.formData, 'dataType', 'dataset')
      } else {
        this.lineChartDataId = value
        this.$set(this.formData, 'subDataId', value)
        this.$set(this.formData, 'subDataType', 'dataset')
        this.$set(this.formData, 'labelKeyObj', null)
        this.$set(this.formData, 'valueKeyObjList', null)
        this.fetchDatasetColumns(value)
      }

      if (!this.graphDataId || !this.lineChartDataId) {
        return
      }
      this.$emit('change', 'dataId', {
        id: this.graphDataId,
        type: 'dataset',
        subDataId: this.lineChartDataId,
      })
    } else {
      this.$set(this.formData, 'dataId', value)
      this.$set(this.formData, 'dataType', 'dataset')
      this.$emit('change', 'dataId', {
        id: value,
        type: 'dataset',
      })
    }
  }

  /**
   * 关联字段更改
   */
  private handleCombineFieldChange(value: string) {
    if (!value) {
      return
    }
    this.$set(this.formData, 'combineField', value)
    this.$emit('change', 'combineField', value)
  }

  /**
   * 获取列字段
   */
  private async fetchDatasetColumns(value: string | number) {
    const {
      data: { code, result },
    } = await queryWidgetColumn({
      data: {
        ...this.queryColumnParams,
        id: +value,
        type: 'dataset',
      },
    })

    if (code === 100) {
      this.datasetTableColumn = result.head || []
    }
  }

  /**
   * form 值变化
   */
  private onFormValueChange(fieldName: string, fieldValue: any) {
    this.$set(this.formData, fieldName, fieldValue)
    this.$set(this.formData, 'subChartOptions', {
      ...this.defaultSubChartOptions,
      ...this.formData.subChartOptions,
      [fieldName]: fieldValue,
    })
    const widgetJson = convertFormDataToWidgetJson(
      this.formData,
      this.chartType,
      this.datasetTableColumn
    )
    this.$set(this.formData, 'widgetInfo', {
      id: this.formData.subDataId,
      type: this.formData.dataType,
      widgetJson,
    })
    this.$emit('change', fieldName, fieldValue)
  }

  /**
   * 处理维度和度量的sort发生变化时的联动
   * 保证只实现最新的sort
   */
  private onSortChange(fieldName: string, sortValue: string) {
    console.log(fieldName, sortValue)
    this.$set(this.formData, fieldName, sortValue)
  }

  /**
   * 1、graph-linechart 需要处理subChartOptions 以及将 subChartOptions
   * 放到 graph 的node 配置中
   * 2、update edge directed
   */
  private bindGraphLineChartSubChartOptions(config: IKeyValue) {
    this.$set(this.formData, 'subChartOptions', {
      ...this.formData.subChartOptions,
      ...config,
    })
    const value = this.formData.value || {}
    ;(value.nodes || []).forEach((node: IKeyValue) => {
      node.subChartOptions = {
        ...(node.subChartOptions || {}),
        ...config,
      }
    })
    const { edgeDirected } = config

    // update edge directed
    if (value.edges[0] && value.edges[0].directed !== edgeDirected) {
      ;(value.edges || []).forEach((edge: IKeyValue) => {
        edge.directed = edgeDirected
      })
    }
  }

  private onPropertyChange(config: IKeyValue) {
    if (this.isGraphLineChart) {
      this.bindGraphLineChartSubChartOptions(config)
    }
    this.$emit('propertyChange', config)
  }

  private onTopNChange(event: Event) {
    const value = +(<HTMLInputElement>event.target)?.value
    if (value === 0 || !value) {
      this.$message.error('topN 不能为空')
      return
    }
    if (value > 9999) {
      this.$message.warning('topN数值太大，建议重新调整')
      return
    }
    if (value !== this.formData.topN) {
      this.onFormValueChange('topN', value)
    }
  }
}
</script>

<style lang="less" scoped>
.form {
  /deep/ .ant-select {
    width: 100%;
  }

  .form-item {
    line-height: 40px;
  }
}

.panel-title {
  font-weight: bolder;
  height: 40px;
  line-height: 40px;
  margin-top: 4px;
  position: relative;
  width: 100%;

  .anticon {
    font-size: 8px;
    font-weight: normal;
    height: 40px;
    line-height: 40px;
    position: absolute;
    right: 10px;
  }

  .panel-title-hr {
    background-color: #e9e9e9;
    height: 1px;
    left: -16px;
    position: absolute;
    right: -20px;
  }
}
</style>
